// ==============================================================================================
// ╦  ┬┌─┐┌─┐┌┐┌┌─┐┌─┐    Yaksha Programming Language
// ║  ││  ├┤ │││└─┐├┤     is Licensed with GPLv3 + extra terms. Please see below.
// ╩═╝┴└─┘└─┘┘└┘└─┘└─┘
// Note: libs - MIT license, runtime/3rd - various
// ==============================================================================================
// GPLv3:
//
// Yaksha - Programming Language.
// Copyright (C) 2020 - 2024 Bhathiya Perera
//
// This program is free software: you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with this program.
// If not, see https://www.gnu.org/licenses/.
//
// ==============================================================================================
// Additional Terms:
//
// Please note that any commercial use of the programming language's compiler source code
// (everything except compiler/runtime, compiler/libs and compiler/3rd) require a written agreement
// with author of the language (Bhathiya Perera).
//
// If you are using it for an open source project, please give credits.
// Your own project must use GPLv3 license with these additional terms.
//
// You may use programs written in Yaksha/YakshaLisp for any legal purpose
// (commercial, open-source, closed-source, etc) as long as it agrees
// to the licenses of linked runtime libraries (see compiler/runtime/README.md).
//
// ==============================================================================================
// ic_ast.h
// generated by ic_update_ast.py
#ifndef IC_AST_H
#define IC_AST_H
#include "ic_token.h"
#include <vector>
namespace yaksha {
  // ------ forward declarations ------
  struct ic_expr;
  struct ic_stmt;
  struct ic_parameter;
  struct ic_assign_expr;
  struct ic_pp_block_stmt;
  struct ic_pp_code_line_stmt;
  struct ic_pp_define_function_stmt;
  struct ic_pp_define_normal_stmt;
  struct ic_pp_elif_line_stmt;
  struct ic_pp_else_line_stmt;
  struct ic_pp_endif_line_stmt;
  struct ic_pp_error_stmt;
  struct ic_pp_if_stmt;
  struct ic_pp_if_line_stmt;
  struct ic_pp_ifdef_line_stmt;
  struct ic_pp_ifndef_line_stmt;
  struct ic_pp_include_stmt;
  struct ic_pp_line_stmt;
  struct ic_pp_pragma_stmt;
  struct ic_pp_undef_stmt;
  struct ic_pp_warning_stmt;
  // Types of expressions and statements
  enum class ic_ast_type {
    EXPR_ASSIGN,
    STMT_PP_BLOCK,
    STMT_PP_CODE_LINE,
    STMT_PP_DEFINE_FUNCTION,
    STMT_PP_DEFINE_NORMAL,
    STMT_PP_ELIF_LINE,
    STMT_PP_ELSE_LINE,
    STMT_PP_ENDIF_LINE,
    STMT_PP_ERROR,
    STMT_PP_IF,
    STMT_PP_IF_LINE,
    STMT_PP_IFDEF_LINE,
    STMT_PP_IFNDEF_LINE,
    STMT_PP_INCLUDE,
    STMT_PP_LINE,
    STMT_PP_PRAGMA,
    STMT_PP_UNDEF,
    STMT_PP_WARNING
  };
  // ------ expression visitor ------
  struct ic_expr_visitor {
    virtual void visit_ic_assign_expr(ic_assign_expr *obj) = 0;
    virtual ~ic_expr_visitor() = default;
  };
  // ------ statement visitor ------
  struct ic_stmt_visitor {
    virtual void visit_ic_pp_block_stmt(ic_pp_block_stmt *obj) = 0;
    virtual void visit_ic_pp_code_line_stmt(ic_pp_code_line_stmt *obj) = 0;
    virtual void
    visit_ic_pp_define_function_stmt(ic_pp_define_function_stmt *obj) = 0;
    virtual void
    visit_ic_pp_define_normal_stmt(ic_pp_define_normal_stmt *obj) = 0;
    virtual void visit_ic_pp_error_stmt(ic_pp_error_stmt *obj) = 0;
    virtual void visit_ic_pp_if_stmt(ic_pp_if_stmt *obj) = 0;
    virtual void visit_ic_pp_include_stmt(ic_pp_include_stmt *obj) = 0;
    virtual void visit_ic_pp_line_stmt(ic_pp_line_stmt *obj) = 0;
    virtual void visit_ic_pp_pragma_stmt(ic_pp_pragma_stmt *obj) = 0;
    virtual void visit_ic_pp_undef_stmt(ic_pp_undef_stmt *obj) = 0;
    virtual void visit_ic_pp_warning_stmt(ic_pp_warning_stmt *obj) = 0;
    virtual ~ic_stmt_visitor() = default;
  };
  // ------ expression base class ------
  struct ic_expr {
    virtual ~ic_expr() = default;
    virtual void accept(ic_expr_visitor *v) = 0;
    virtual ic_ast_type get_type() = 0;
  };
  // ------- statement base class ------
  struct ic_stmt {
    virtual ~ic_stmt() = default;
    virtual void accept(ic_stmt_visitor *v) = 0;
    virtual ic_ast_type get_type() = 0;
  };
  // ------- expressions ------
  struct ic_assign_expr : ic_expr {
    ic_assign_expr(ic_token *name, ic_token *opr, ic_expr *right);
    void accept(ic_expr_visitor *v) override;
    ic_ast_type get_type() override;
    ic_token *name_;
    ic_token *opr_;
    ic_expr *right_;
  };
  // ------- statements ------
  struct ic_pp_block_stmt : ic_stmt {
    explicit ic_pp_block_stmt(std::vector<ic_stmt *> statements);
    void accept(ic_stmt_visitor *v) override;
    ic_ast_type get_type() override;
    std::vector<ic_stmt *> statements_;
  };
  struct ic_pp_code_line_stmt : ic_stmt {
    ic_pp_code_line_stmt(std::vector<ic_token *> token_string,
                         ic_token *t_newline);
    void accept(ic_stmt_visitor *v) override;
    ic_ast_type get_type() override;
    std::vector<ic_token *> token_string_;
    ic_token *t_newline_;
  };
  struct ic_pp_define_function_stmt : ic_stmt {
    ic_pp_define_function_stmt(ic_token *t_hash, ic_token *t_define,
                               ic_token *t_identifier, ic_token *t_paren_open,
                               std::vector<ic_token *> params,
                               ic_token *t_paren_close,
                               std::vector<ic_token *> token_string);
    void accept(ic_stmt_visitor *v) override;
    ic_ast_type get_type() override;
    ic_token *t_hash_;
    ic_token *t_define_;
    ic_token *t_identifier_;
    ic_token *t_paren_open_;
    std::vector<ic_token *> params_;
    ic_token *t_paren_close_;
    std::vector<ic_token *> token_string_;
  };
  struct ic_pp_define_normal_stmt : ic_stmt {
    ic_pp_define_normal_stmt(ic_token *t_hash, ic_token *t_define,
                             ic_token *t_identifier,
                             std::vector<ic_token *> token_string);
    void accept(ic_stmt_visitor *v) override;
    ic_ast_type get_type() override;
    ic_token *t_hash_;
    ic_token *t_define_;
    ic_token *t_identifier_;
    std::vector<ic_token *> token_string_;
  };
  struct ic_pp_elif_line_stmt : ic_stmt {
    ic_pp_elif_line_stmt(ic_token *t_hash, ic_token *t_elif_t,
                         std::vector<ic_token *> if_expression, ic_stmt *block);
    void accept(ic_stmt_visitor *v) override;
    ic_ast_type get_type() override;
    ic_token *t_hash_;
    ic_token *t_elif_t_;
    std::vector<ic_token *> if_expression_;
    ic_stmt *block_;
  };
  struct ic_pp_else_line_stmt : ic_stmt {
    ic_pp_else_line_stmt(ic_token *t_hash, ic_token *t_else_t, ic_stmt *block);
    void accept(ic_stmt_visitor *v) override;
    ic_ast_type get_type() override;
    ic_token *t_hash_;
    ic_token *t_else_t_;
    ic_stmt *block_;
  };
  struct ic_pp_endif_line_stmt : ic_stmt {
    ic_pp_endif_line_stmt(ic_token *t_hash, ic_token *t_elif_t);
    void accept(ic_stmt_visitor *v) override;
    ic_ast_type get_type() override;
    ic_token *t_hash_;
    ic_token *t_elif_t_;
  };
  struct ic_pp_error_stmt : ic_stmt {
    ic_pp_error_stmt(ic_token *t_hash, ic_token *t_error,
                     std::vector<ic_token *> token_string);
    void accept(ic_stmt_visitor *v) override;
    ic_ast_type get_type() override;
    ic_token *t_hash_;
    ic_token *t_error_;
    std::vector<ic_token *> token_string_;
  };
  struct ic_pp_if_stmt : ic_stmt {
    ic_pp_if_stmt(ic_stmt *if_t, std::vector<ic_stmt *> elifs, ic_stmt *else_t,
                  ic_stmt *endif_t);
    void accept(ic_stmt_visitor *v) override;
    ic_ast_type get_type() override;
    ic_stmt *if_t_;
    std::vector<ic_stmt *> elifs_;
    ic_stmt *else_t_;
    ic_stmt *endif_t_;
  };
  struct ic_pp_if_line_stmt : ic_stmt {
    ic_pp_if_line_stmt(ic_token *t_hash, ic_token *t_if_t,
                       std::vector<ic_token *> if_expression, ic_stmt *block);
    void accept(ic_stmt_visitor *v) override;
    ic_ast_type get_type() override;
    ic_token *t_hash_;
    ic_token *t_if_t_;
    std::vector<ic_token *> if_expression_;
    ic_stmt *block_;
  };
  struct ic_pp_ifdef_line_stmt : ic_stmt {
    ic_pp_ifdef_line_stmt(ic_token *t_hash, ic_token *t_ifdef_t,
                          ic_token *t_identifier, ic_stmt *block);
    void accept(ic_stmt_visitor *v) override;
    ic_ast_type get_type() override;
    ic_token *t_hash_;
    ic_token *t_ifdef_t_;
    ic_token *t_identifier_;
    ic_stmt *block_;
  };
  struct ic_pp_ifndef_line_stmt : ic_stmt {
    ic_pp_ifndef_line_stmt(ic_token *t_hash, ic_token *t_ifndef_t,
                           ic_token *t_identifier, ic_stmt *block);
    void accept(ic_stmt_visitor *v) override;
    ic_ast_type get_type() override;
    ic_token *t_hash_;
    ic_token *t_ifndef_t_;
    ic_token *t_identifier_;
    ic_stmt *block_;
  };
  struct ic_pp_include_stmt : ic_stmt {
    ic_pp_include_stmt(ic_token *t_hash, ic_token *t_include,
                       ic_token *t_path_spec);
    void accept(ic_stmt_visitor *v) override;
    ic_ast_type get_type() override;
    ic_token *t_hash_;
    ic_token *t_include_;
    ic_token *t_path_spec_;
  };
  struct ic_pp_line_stmt : ic_stmt {
    ic_pp_line_stmt(ic_token *t_hash, ic_token *t_line, ic_token *t_line_number,
                    ic_token *t_path_spec);
    void accept(ic_stmt_visitor *v) override;
    ic_ast_type get_type() override;
    ic_token *t_hash_;
    ic_token *t_line_;
    ic_token *t_line_number_;
    ic_token *t_path_spec_;
  };
  struct ic_pp_pragma_stmt : ic_stmt {
    ic_pp_pragma_stmt(ic_token *t_hash, ic_token *t_pragma,
                      std::vector<ic_token *> token_string);
    void accept(ic_stmt_visitor *v) override;
    ic_ast_type get_type() override;
    ic_token *t_hash_;
    ic_token *t_pragma_;
    std::vector<ic_token *> token_string_;
  };
  struct ic_pp_undef_stmt : ic_stmt {
    ic_pp_undef_stmt(ic_token *t_hash, ic_token *t_undef,
                     ic_token *t_identifier);
    void accept(ic_stmt_visitor *v) override;
    ic_ast_type get_type() override;
    ic_token *t_hash_;
    ic_token *t_undef_;
    ic_token *t_identifier_;
  };
  struct ic_pp_warning_stmt : ic_stmt {
    ic_pp_warning_stmt(ic_token *t_hash, ic_token *t_warning,
                       std::vector<ic_token *> token_string);
    void accept(ic_stmt_visitor *v) override;
    ic_ast_type get_type() override;
    ic_token *t_hash_;
    ic_token *t_warning_;
    std::vector<ic_token *> token_string_;
  };
  // ------- utils ------
  struct ic_ast_pool {
    ic_ast_pool();
    ~ic_ast_pool();
    ic_expr *ic_c_assign_expr(ic_token *name, ic_token *opr, ic_expr *right);
    ic_stmt *ic_c_pp_block_stmt(std::vector<ic_stmt *> statements);
    ic_stmt *ic_c_pp_code_line_stmt(std::vector<ic_token *> token_string,
                                    ic_token *t_newline);
    ic_stmt *ic_c_pp_define_function_stmt(ic_token *t_hash, ic_token *t_define,
                                          ic_token *t_identifier,
                                          ic_token *t_paren_open,
                                          std::vector<ic_token *> params,
                                          ic_token *t_paren_close,
                                          std::vector<ic_token *> token_string);
    ic_stmt *ic_c_pp_define_normal_stmt(ic_token *t_hash, ic_token *t_define,
                                        ic_token *t_identifier,
                                        std::vector<ic_token *> token_string);
    ic_stmt *ic_c_pp_elif_line_stmt(ic_token *t_hash, ic_token *t_elif_t,
                                    std::vector<ic_token *> if_expression,
                                    ic_stmt *block);
    ic_stmt *ic_c_pp_else_line_stmt(ic_token *t_hash, ic_token *t_else_t,
                                    ic_stmt *block);
    ic_stmt *ic_c_pp_endif_line_stmt(ic_token *t_hash, ic_token *t_elif_t);
    ic_stmt *ic_c_pp_error_stmt(ic_token *t_hash, ic_token *t_error,
                                std::vector<ic_token *> token_string);
    ic_stmt *ic_c_pp_if_stmt(ic_stmt *if_t, std::vector<ic_stmt *> elifs,
                             ic_stmt *else_t, ic_stmt *endif_t);
    ic_stmt *ic_c_pp_if_line_stmt(ic_token *t_hash, ic_token *t_if_t,
                                  std::vector<ic_token *> if_expression,
                                  ic_stmt *block);
    ic_stmt *ic_c_pp_ifdef_line_stmt(ic_token *t_hash, ic_token *t_ifdef_t,
                                     ic_token *t_identifier, ic_stmt *block);
    ic_stmt *ic_c_pp_ifndef_line_stmt(ic_token *t_hash, ic_token *t_ifndef_t,
                                      ic_token *t_identifier, ic_stmt *block);
    ic_stmt *ic_c_pp_include_stmt(ic_token *t_hash, ic_token *t_include,
                                  ic_token *t_path_spec);
    ic_stmt *ic_c_pp_line_stmt(ic_token *t_hash, ic_token *t_line,
                               ic_token *t_line_number, ic_token *t_path_spec);
    ic_stmt *ic_c_pp_pragma_stmt(ic_token *t_hash, ic_token *t_pragma,
                                 std::vector<ic_token *> token_string);
    ic_stmt *ic_c_pp_undef_stmt(ic_token *t_hash, ic_token *t_undef,
                                ic_token *t_identifier);
    ic_stmt *ic_c_pp_warning_stmt(ic_token *t_hash, ic_token *t_warning,
                                  std::vector<ic_token *> token_string);

private:
    std::vector<ic_expr *> cleanup_expr_;
    std::vector<ic_stmt *> cleanup_stmt_;
  };
  /**
  * Parameter for a user defined function declaration
  */
  struct ic_parameter {
    ic_token *name_;
    std::vector<ic_token *> data_type_;
  };
}// namespace yaksha
#endif
